﻿/*-------------------------------------------------------------------------
* 命名空间: WaferSelectV3.Common/SocketServer
* 类       名: SocketServer
* 功      能:  TD
* 时      间:  2024-05-15 13:54:33
* 版      本:  V1.0
* 作      者:  Fioman
* 格      言:  Talk is cheap,show me the code ^_^
*-------------------------------------------------------------------------*/
using log4net.Util;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.Tracing;
using System.Drawing.Printing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WaferSelectV3.Extensions;
using WaferSelectV3.Models;
using WaferSelectV3.Services;

namespace WaferSelectV3.Common
{
    public class SocketServer
    {
        public SocketServer(SlaveStateModel slaveState)
        {
            _slaveState = slaveState;
            _clientName = _slaveState.SlaveName;
        }
        // ViewModel中的SlaveState,用来更新其状态
        private SlaveStateModel _slaveState;
        // 从站名称
        private string? _clientName;
        // 消息头部类型,每个类型代表一种消息
        private string? msgHeader;
        /// <summary>
        /// 相机编号
        /// </summary>
        private string? cameraNum;
        private TcpListener? _listener;
        /// <summary>
        /// 已经连接的TcpClientConnected对象,如果没有连接,就是null.
        /// 每个PcpServer负责一个客户端,如果之前已经有连接了,就先关闭掉
        /// </summary>
        private TcpClient? TcpClientConnected = null;
        /// <summary>
        /// 清空消息是否收到回复
        /// </summary>
        public bool ClearResponseIsOk = false;

        public async Task StartServerAsync(CancellationTokenSource tokenParent)
        {
            try
            {
                // IPAddress.Any:表示接受来自所有网络接口的传入连接.
                _listener = new TcpListener(IPAddress.Any, _slaveState.SlavePort);
                // 是否允许共享监听地址,设置为false的时候表示允许多个TcpListener实例同时绑定到同一个IP地址和端口上
                // 如果设置为true,表示只能绑定到不同的ip地址和端口上
                _listener.ExclusiveAddressUse = false;
                _listener.Start();
                while (!tokenParent.IsCancellationRequested)
                {
                    string msg = string.Empty;
                    LoggerHelper.WriteLogMain($"负责从站 ({_clientName}) 的服务器已经开启");
                    TcpClient client = await _listener.AcceptTcpClientAsync(tokenParent.Token);

                    if (tokenParent.IsCancellationRequested)
                    {
                        break;
                    }
                    // 判断IP地址是否正确,如果IP地址不正确,不准予连接
                    IPAddress clientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint!).Address;
                    if (clientIpAddress.ToString() != _slaveState.SlaveIp)
                    {
                        msg = $"{clientIpAddress} 连接上来了,因为从站({_clientName})设置的IP地址为{_slaveState.SlaveIp},所以连接不予以处理";
                        LoggerHelper.WriteLogMain(msg);
                    }
                    else
                    {
                        msg = $"从站 {_clientName},  {clientIpAddress} 已经连接,开始收发消息.";
                    }
                    if (TcpClientConnected != null)
                    {
                        TcpClientConnected?.Dispose();
                        TcpClientConnected?.Close();
                        TcpClientConnected = null;
                    }
                    TcpClientConnected = client;
                    _slaveState.IsOnline = true;
                    _slaveState.DisConnectedCount = 0;
                    await AcceptClientMsgAsync(tokenParent);
                }
            }
            catch (OperationCanceledException)
            {
                string msg = $"从站({_clientName}) 的监听任务被取消";
                LoggerHelper.WriteLogMain(msg);
            }
            catch (Exception ex)
            {
                string msg = ex.GetFullException();
                LoggerHelper.WriteLogMain(msg, LogType.Exception);
            }
            finally
            {
                _slaveState.ReadyStatus = false;
                if (TcpClientConnected != null)
                {
                    TcpClientConnected?.Dispose();
                    TcpClientConnected?.Close();
                    TcpClientConnected = null;
                }
                if (_listener != null)
                {
                    _listener.Stop();
                    _listener = null;
                }

                LoggerHelper.WriteLogMain($"从站 ({_clientName}) 服务器监听任务关闭");
            }

        }

        /// <summary>
        /// 处理接收消息的异步任务
        /// </summary>
        /// <param name="tokenParent"></param>
        /// <returns></returns>
        private async Task AcceptClientMsgAsync(CancellationTokenSource tokenParent)
        {
            try
            {
                using (NetworkStream stream = TcpClientConnected?.GetStream()!)
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while (!tokenParent.IsCancellationRequested)
                    {
                        bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, tokenParent.Token);
                        if (tokenParent.IsCancellationRequested)
                        {
                            stream.Close();
                            break;
                        }
                        if (bytesRead == 0)
                        {
                            _slaveState.IsOnline = false;
                            stream.Close();
                            LoggerHelper.WriteLogMain($"从站 {_clientName} 接收到的数据长度为0,连接已经断开,接收消息任务关闭");
                            break;
                        }

                        string msgReceive;
                        msgReceive = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        LoggerHelper.WriteLogWithClient(msgReceive, _clientName);
                        DataResult parseMsgRes = ParseMsgFromSlave(msgReceive);
                    }
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        private DataResult ParseMsgFromSlave(string msgReceive)
        {
            DataResult result = new DataResult();

            try
            {
                string[] subMsg = msgReceive.Split(new[] { "End" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string s in subMsg)
                {
                    string singleMsg = s.TrimEnd() + "End";
                    string msgHeader = singleMsg.Split(',', StringSplitOptions.TrimEntries)[0];
                    if (!ConstantProvider.MsgHeaderClientMap.ContainsKey(msgHeader))
                    {
                        result.Message = $"消息类型错误消息都不再预设的消息头和模块对应的字典映射中,错误的消息为:{msgReceive}";
                        return result;
                    }
                    string headerClientName = ConstantProvider.MsgHeaderClientMap[msgHeader];
                    if (headerClientName == "尺寸")
                    {
                        // 处理尺寸工位的消息
                        DataResult<List<string>> sizeClientRes = MsgParserHelper.ParseSizeClientMsg(msgReceive);
                        if (sizeClientRes.State)
                        {
                            List<string> sizeData = sizeClientRes.Data!;
                            int waferId = Convert.ToInt32(sizeData[0]);
                            string cameraNum = sizeData[2];
                            if (sizeData.Count == 4)
                            {
                                // 收到错误消息或者是队列清空回复
                                string errorCode = sizeData[3];
                                if (errorCode.Equals("ClearOK", StringComparison.OrdinalIgnoreCase))
                                {
                                    ClearResponseIsOk = true;
                                    LoggerHelper.WriteLogMain($"{headerClientName}: 收到清空队列信号回复");
                                }
                                else
                                {
                                    // 发送消息给视觉,错误消息回复
                                    _ = SendMsgAsync(MsgPackHelper.GetErrorCodeResponseMsgSend(msgHeader, cameraNum, waferId, errorCode));
                                    string errorInfo;
                                    if (MsgParserHelper.VisionErrorCodeMap.ContainsKey(errorCode))
                                    {
                                        errorInfo = MsgParserHelper.VisionErrorCodeMap[errorCode];
                                    }
                                    else
                                    {
                                        errorInfo = "消息错误码不再错误码提供的字典映射中,请检查修正";
                                    }
                                    LoggerHelper.WriteLogWithClient($"{headerClientName}: 收到视觉检测错误消息,错误码为:{errorCode},错误描述:{errorInfo}", _clientName);
                                    if (!GlobalValues.ShieldModules.Contains(headerClientName))
                                    {
                                        // 将解析的等级写入到物料等级字典中去
                                        WriteErrorLevelToWaferLevel(waferId, errorCode, errorInfo);
                                    }
                                }
                            }
                            else
                            {
                                // 收到正确的消息,尺寸工位消息处理
                                WriteNormalLevelToWaferLevel(waferId, msgHeader, cameraNum, sizeData.Skip(3).Take(sizeData.Count - 3).ToList());
                                _ = SendMsgAsync(MsgPackHelper.GetOkResponseMsgSend(msgHeader, cameraNum, waferId));
                            }
                        }
                        else
                        {
                            LoggerHelper.WriteLogMain(sizeClientRes.Message!, LogType.Fatal);
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                result.Message = ex.GetFullException();
            }
            return result;
        }

        private void WriteNormalLevelToWaferLevel(int waferId, string msgHeader, string cameraNum, List<string> list)
        {
            try
            {
                Dictionary<string, List<int>> levelMap = new Dictionary<string, List<int>>();
                // 如果规则已经存在了,就不用赋值了
                if (GlobalValues.WaferIdLevelDictionary.ContainsKey(waferId))
                {
                    levelMap = GlobalValues.WaferIdLevelDictionary[waferId];
                }
                else
                {
                    GlobalValues.WaferIdLevelDictionary[waferId] = levelMap;
                }
                if (msgHeader == "Size")
                {

                }
            }
            catch (Exception ex)
            {

                throw;
            }
        }

        /// <summary>
        /// 将错误消息写入到等级类型中
        /// 00: 3D工位误触发
        /// 01:  连片
        /// 02: 反向
        /// 03: 遮挡
        /// 04: 碎片
        /// 05: 错位
        /// 06: PLC通讯异常
        /// 07: 3D数据错乱
        /// 对应写入给Plc的异常位置为1,2,3,4,5
        /// </summary>
        /// <param name="waferId"></param>
        /// <param name="errorCode"></param>
        private void WriteErrorLevelToWaferLevel(int waferId, string errorCode, string errorInfo)
        {
            Dictionary<string, List<int>> levelMap = new Dictionary<string, List<int>>();
            if (GlobalValues.WaferIdLevelDictionary.ContainsKey(waferId))
            {
                levelMap = GlobalValues.WaferIdLevelDictionary[waferId];
            }
            GlobalValues.VisionErrorWithWaferId[waferId] = errorInfo;
            LoggerHelper.WriteLogMain(errorInfo);
            switch (errorCode)
            {

                case "00": // 3D工位误触发
                    levelMap[errorInfo] = new List<int> { 36 };
                    break;
                case "01":
                    levelMap[errorInfo] = new List<int> { 32 };
                    break;
                case "02":
                    levelMap[errorInfo] = new List<int> { 32 };
                    break;
                case "03":
                    levelMap[errorInfo] = new List<int> { 33 };
                    break;
                case "04":
                    levelMap[errorInfo] = new List<int> { 32 };
                    break;
                case "05":
                    levelMap[errorInfo] = new List<int> { 34 };
                    break;
                case "06":
                    levelMap[errorInfo] = new List<int> { 35 };
                    break;
                case "07":
                    levelMap[errorInfo] = new List<int> { 37 };
                    break;
                default:
                    levelMap[errorInfo] = new List<int> { 32 };
                    break;
            }
        }

        /// <summary>
        /// 异步发送消息
        /// </summary>
        /// <param name="msgSend"></param>
        /// <returns></returns>
        public async Task SendMsgAsync(byte[] msgSend)
        {
            if (TcpClientConnected == null)
            {
                LoggerHelper.WriteLogWithClient($"{msgSend} 发送失败,连接已经断开", _clientName);
                NetworkStream? stream = TcpClientConnected?.GetStream();
                if (stream != null)
                {
                    await stream.WriteAsync(msgSend, 0, msgSend.Length);
                    LoggerHelper.WriteLogWithClient($"{Encoding.ASCII.GetString(msgSend)} 消息发送成功", _clientName);
                }
            }
        }
    }
}
